package com.zeta.plan.bloom;

import com.google.common.base.Preconditions;
import com.google.common.hash.Funnel;
import com.google.common.hash.Hashing;

/**
 * @ClassName BloomFilterHelper
 * @Description 借助guava和redis实现布隆过滤器
 * @Author zeta
 * @Date 2022/2/28 16:56
 * @Version 1.0
 **/
public class BloomFilterHelper<T> {
    // 哈希函数的数量
    private int numHashFunction;
    // 位图的大小
    private int bitSize;

    private Funnel<T> funnel;

    public BloomFilterHelper(Funnel<T> funnel, int expectedInsertions, double falsePositiveProbability) {
        Preconditions.checkArgument(funnel != null, "funnel不能为空");
        this.funnel = funnel;
        this.bitSize = optimalSizeOfBitMap(expectedInsertions, falsePositiveProbability);

    }

    /**
     * 计算数据经过k个hash函数得到的offset
     * 可以用2个哈希函数来模拟k个哈希函数，即gi(x) = h1(x) + ih2(x) ，其中0<=i<=k-1；
     * @param value
     * @return
     */
    public int[] murmurHashOffset(T value) {
        int[] offsets = new int[numHashFunction];

        long hash64 = Hashing.murmur3_128().hashObject(value, funnel).asLong();
        int hash1 = (int) hash64;
        int hash2 = (int) (hash64 >>> 32);
        for (int i = 0; i < numHashFunction; i++) {
            int hash = hash1 + (i + 1) * hash2;
            if (hash < 0) {
                hash = ~hash;
            }
            offsets[i] = hash % bitSize;
        }
        return offsets;
    }

    /**
     *  m = - (nlnfpp)/(ln2)^2
     *  计算位图的长度
     * @param expectedInsertions
     * @param falsePositiveProbability
     * @return
     */
    private int optimalSizeOfBitMap(int expectedInsertions, double falsePositiveProbability) {
        if (falsePositiveProbability == 0) {
            falsePositiveProbability = Double.MIN_VALUE; // 4.9e-324
        }
        int size = (int) (-expectedInsertions * Math.log(falsePositiveProbability) / Math.pow(Math.log(2), 2));
        return size;
    }

    /**
     * k = -lnfpp / ln2
     * 计算哈希函数的数量
     * @param falsePositiveProbability
     * @return
     */
    private int optimalNumOfHashFunction(double falsePositiveProbability) {
        if (falsePositiveProbability == 0) {
            falsePositiveProbability = Double.MIN_VALUE; // 4.9e-324
        }
        int k = (int) (-Math.log(falsePositiveProbability) / Math.log(2));
        return k;
    }

    /**
     * k = (m/n)ln2
     * 计算哈希函数的数量
     * @param bitSize
     * @param expectedInsertions
     * @return
     */
    private int optimalNumOfHashFunction(int bitSize, int expectedInsertions) {
        int k = (int) ((bitSize / expectedInsertions) * Math.log(2));
        return k;
    }


}
